package com.example.xcService.pojo.channels.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.xcService.pojo.channels.ChannelResult;
import com.example.xcService.pojo.channels.ChannelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.*;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;


/*
*  上海仁跃
* */
@Slf4j
public class Plugin_ECARD_P030 implements ChannelService {

    public static final String CHARSET = "UTF-8";
    //密钥算法
    public static final String ALGORITHM_RSA = "RSA";
    //RSA 签名算法
    public static final String ALGORITHM_RSA_SIGN = "SHA256WithRSA";
    public static final int ALGORITHM_RSA_PRIVATE_KEY_LENGTH = 2048;
    @Override
    public ChannelResult QueryBalance(JSONObject apiConfig) {
        System.out.println("成功调用了QueryBalance");
        return ChannelResult.success("success");
    }

    @Override
    public ChannelResult Submit(JSONObject apiConfig, Map<String, Object> data) {
       try{
           String supProductId = String.valueOf(data.get("SUPProductId"));
           String[] s = supProductId.split("_");

           TreeMap<String, String> map = new TreeMap<String, String>();
           String timestamp=System.currentTimeMillis() / 1000 + "";//时间戳
           map.put("MerchantNo",apiConfig.getString("AppId"));//商户账号
           map.put("ProductCode",s[0]);//商品编码
           map.put("RechargeNum","1");//充值数量
           map.put("RechargeNo",String.valueOf(data.get("AccountVal")));//充值账号
           map.put("ThirdOrderNo",String.valueOf(data.get("ChannelOrderCode")));//商户单号
           map.put("FaceValue",String.valueOf(data.get("ProductPrice")));//标准面值 - 元

           if (s.length ==2){
               map.put("AgreedPrice",s[1]);
           }else {
               map.put("AgreedPrice",String.valueOf(data.get("PurchasePrice"))); //* 结算价格(AgreedPrice) = 标准面值(FaceValue) * 约定折扣(商务密价)
           }
           map.put("TimeStamp",timestamp);//时间戳
           map.put("CallbackUrl",apiConfig.getString("CallBackUrl"));//回调地址

           String host = apiConfig.getString("Host");//域名
           String submitUrl = apiConfig.getString("SubmitUrl");//下单地址
           //签名加密
           log.info("上海仁跃下单加密前参数"+map);
           String pemSecret = apiConfig.getString("PemSecret");
           String sign = verifyString(map, apiConfig.getString("AppSecret"),pemSecret);
           map.put("SignSecret",sign);
           Map<String,String> header=new HashMap<String, String>();
           header.put("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
           HttpResponse response =doPost(host, submitUrl,header, map, null);
           String backHtml= EntityUtils.toString(response.getEntity());
           log.info("上海仁跃下单返回"+backHtml);
           JSONObject resParams = JSONObject.parseObject(backHtml);
           String codeRes = resParams.getString("CodeRes");
           String message = resParams.getString("Message");
           if (codeRes.equals("1000") || codeRes.equals("1012")){
                return ChannelResult.IN_PROCESS("充值中");
           }
           if(codeRes.equals("1004")||codeRes.equals("1017")||codeRes.equals("1019")
                   ||codeRes.equals("1027")||codeRes.equals("8017")||codeRes.equals("8049")||codeRes.equals("8044")){
               return ChannelResult.error(message);
           }
           return ChannelResult.FAILED(message);
       }catch (Exception e) {
           e.printStackTrace();
           log.error("仁跃提交订单接口错误：",e);
           return  ChannelResult.error("仁跃提交订单接口错误");
       }
    }

    public static void main(String[] args) {
        String str= "30540123";
        String[] s = str.split("_");
        if (s.length==2){
            System.out.println("长度为2");
        }else {
            System.out.println("长度为1");
        }
        System.out.println(s[0]);

    }

    @Override
    public ChannelResult Query(JSONObject apiConfig, Map<String, Object> data) {
        try {
            TreeMap<String, String> map = new TreeMap<String, String>();
            String timestamp=System.currentTimeMillis() / 1000 + "";//时间戳
            map.put("MerchantNo",apiConfig.getString("AppId"));//商户账号
            map.put("ThirdOrderNo",String.valueOf(data.get("ChannelOrderCode")));//商户单号
            map.put("TimeStamp",timestamp);//时间戳
            //签名加密
            log.info("上海仁跃查询加密前参数"+map);
            String pemSecret = apiConfig.getString("PemSecret");
            String sign = verifyString(map, apiConfig.getString("AppSecret"),pemSecret);
            map.put("SignSecret",sign);

            String host = apiConfig.getString("Host");//域名
            String queryUrl = apiConfig.getString("QueryUrl");//下单地址

            Map<String,String> header=new HashMap<String, String>();
            header.put("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
            HttpResponse response =doPost(host, queryUrl,header, map, null);
            String backHtml= EntityUtils.toString(response.getEntity());
            log.info("上海仁跃查询返回"+backHtml);
            JSONObject resParams = JSONObject.parseObject(backHtml);
            String codeRes = resParams.getString("CodeRes");
            String message = resParams.getString("Message");
            String regState = resParams.getString("RegState");
            if (codeRes.equals("1000")){
                if (regState.equals("01")) {
                    return ChannelResult.IN_PROCESS("充值中");
                }
                if (regState.equals("02")){
                    return ChannelResult.success("充值成功");
                }
                if (regState.equals("03")){
                    return ChannelResult.FAILED("充值失败");
                }
                if (regState.equals("04")){
                    return ChannelResult.error("充值异常");
                }
            }
          return ChannelResult.error(message);
        }catch (Exception e) {
            e.printStackTrace();
            log.error("仁跃查询订单接口错误：",e);
            return  ChannelResult.error("仁跃查询订单接口错误");
        }
    }

    @Override
    public ChannelResult Notify(JSONObject apiConfig, Map<String, Object> data) {
        System.out.println("成功调用了Notify");
        return ChannelResult.success("success");
    }


    public static String verifyString(TreeMap<String,String> map , String signKey,String privateKey){
        //签名加密规则：
        //        （1.）设所有发送或者接收到的数据为集合M
        //        （2.）将集合M内非空参数值的参数按照参数名ASCII码从小到大排序 （字典序）
        //        （3.）使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串String
        //        （4.）在String最后拼接上 &MerchantKey=Sign 得到SignTemp字符串
        //        （5.）并对SignTemp进行 SHA256WithRSA 签名算法加密
        //        （6.）再将得到的SignTemp字符串进行base64转换，得到SignSecret值
        try {
            String signTemp="";
            for (Map.Entry<String, String> entry : map.entrySet()) {
                signTemp += entry.getKey()+"="+entry.getValue()+"&";
            }
            signTemp = signTemp +"MerchantKey="+signKey;
            //将签名字符串SHA256WithRSA加密
            return buildRSASignByPrivateKey(signTemp, privateKey);
        } catch (Exception e) {
            //异常自行处理
            e.printStackTrace();
            return "";
        }
    }

    public static String buildRSASignByPrivateKey(String data, String key) {
        try {
            //通过PKCS#8编码的Key指令获得私钥对象
            PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));
            KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
            Signature signature = Signature.getInstance(ALGORITHM_RSA_SIGN);
            signature.initSign(privateKey);
            signature.update(data.getBytes(CHARSET));
            return Base64.encodeBase64String(signature.sign());
        } catch (Exception e) {
            throw new RuntimeException("签名字符串[" + data + "]时遇到异常", e);
        }
    }

    public static HttpResponse doPost(String host, String path,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      Map<String, String> bodys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);
        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        if(headers !=null && !headers.isEmpty()) {
            for (Map.Entry<String, String> e : headers.entrySet()) {
                request.addHeader(e.getKey(), e.getValue());
            }
        }
        if (bodys != null) {
            List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();
            for (String key : bodys.keySet()) {
                nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
            }
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
            formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
            request.setEntity(formEntity);
            log.info("发送仁跃httpPost请求"+"URL"+path+"?"+formEntity);
        }

        return httpClient.execute(request);
    }
    private static HttpClient wrapClient(String host) {
        HttpClient httpClient = new DefaultHttpClient();
        if (host.startsWith("https://")) {
            sslClient(httpClient);
        }
        return httpClient;
    }
    private static void sslClient(HttpClient httpClient) {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(X509Certificate[] xcs, String str) {
                }
                public void checkServerTrusted(X509Certificate[] xcs, String str) {
                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = httpClient.getConnectionManager();
            SchemeRegistry registry = ccm.getSchemeRegistry();
            registry.register(new Scheme("https", 443, ssf));
        } catch (KeyManagementException ex) {
            throw new RuntimeException(ex);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException(ex);
        }
    }
    private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
        StringBuilder sbUrl = new StringBuilder();
        sbUrl.append(host);
        if (!StringUtils.isBlank(path)) {
            sbUrl.append(path);
        }
        if (null != querys) {
            StringBuilder sbQuery = new StringBuilder();
            for (Map.Entry<String, String> query : querys.entrySet()) {
                if (0 < sbQuery.length()) {
                    sbQuery.append("&");
                }
                if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
                    sbQuery.append(query.getValue());
                }
                if (!StringUtils.isBlank(query.getKey())) {
                    sbQuery.append(query.getKey());
                    if (!StringUtils.isBlank(query.getValue())) {
                        sbQuery.append("=");
                        sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
                    }
                }
            }
            if (0 < sbQuery.length()) {
                sbUrl.append("?").append(sbQuery);
            }
        }
        return sbUrl.toString();
    }

}
